package com.googlecode.jasmincc.framework.implementation;

import static com.googlecode.ptrace.Ptrace.ptrace;

import java.util.*;

import com.googlecode.jasmincc.framework.Coordinator;
import com.googlecode.jasmincc.framework.NamingManager;
import com.googlecode.jasmincc.framework.namespace.*;
import com.googlecode.jasmincc.framework.services.*;

public class SimpleNamingManager implements NamingManager {
	protected static List<String> globalDeclarations = new ArrayList<String>();

	protected Coordinator coordinator = null;

	protected NamespaceManager namespaceManager = null;

	protected String grammarName;

	protected String instanceName;

	protected Map<String, String> instances = new Hashtable<String, String>();

	protected boolean isPrimaryGrammar = false;

	protected String qualifiedCorpusName;

	/**
	 * Constructor for derived classes to override.
	 * 
	 */
	protected SimpleNamingManager() {

	}

	public SimpleNamingManager(Map<String, String> instances) {
		this.instances = instances;
	}

	/**
	 * Add a new declaration, such as the name of methods, etc.
	 */
	public void addDeclaration(String name) {
		globalDeclarations.add(name);
	}

	/**
	 * Add a new instance.
	 * @param name the declared name of the instance
	 * @param qualifiedName the qualified name
	 */
	public void addInstance(String name, String qualifiedName) {
		instances.put(name, qualifiedName);
	}

	public void assertNotEqual(String grammarName, String instanceName) throws Exception {
		if (grammarName.equals(instanceName)) {
			throw new Exception("instance name [" + instanceName + "] should be be the same as the grammar name ["
					+ grammarName + "].");
		}
	}

	/**
	 * Build up the qualified name by the current instance name and the
	 * argumented instance name
	 * 
	 * @param grammarName
	 * @param instanceName
	 * @return
	 * @throws RuntimeException
	 */
	public String prefixWithInstanceName(String instanceName) throws UnsupportedOperationException {
		String qualifiedName = instanceName;
		if (!this.instanceName.equals("")) {
			qualifiedName = this.instanceName + "_" + instanceName;
		}
		ptrace(instanceName);
		this.instances.put(instanceName, qualifiedName);
		return qualifiedName;
	}

	/**
	 * Change the name of the reference by adding the prefix of the current
	 * instance name.
	 * 
	 */
	public String changeReferenceName(String tk) throws UnsupportedOperationException {
		// a reference
		int dot = tk.lastIndexOf('.');
		if (dot > 0) {
			// it is a reference of another grammar's production
			ptrace(tk);
			// get the name of the grammar and submit to the
			// coordinator
			String callerName = tk.substring(0, dot);
			String productionName = tk.substring(dot + 1, tk.length());
			String qualifiedCallerName = getQualifiedName(callerName);
			if (qualifiedCallerName == null) {
				// TODO are we going to support this manner of static access?
				// tk = StringUtility.replace(tk, '.', '_');
				// coordinator.addGrammar(callerName);
				throw new UnsupportedOperationException();
			}
			else {
				// it is an instance
				qualifiedCallerName = CharReplacementService.replace(qualifiedCallerName, '.', '_');
				tk = qualifiedCallerName + "_" + productionName;
				ptrace(tk);
			}
		}
		else {
			// it is a production within the current grammar and its
			// ascednents
			tk = prefixWithInstanceName(tk);
			ptrace("prefixed: " + tk);
		}
		return tk;
	}

	/**
	 * Check if there is a declaration with the same name.
	 */
	public boolean containsDeclaration(String name) {
		return globalDeclarations.contains(name);
	}

	/**
	 * Get the coordinator
	 * 
	 * @return the coordinator
	 */
	public Coordinator getCoordinator() {
		return coordinator;
	}

	/**
	 * Get the namespace manager
	 * 
	 * @return the namespace manager
	 */
	public NamespaceManager getCorpusManager() {
		return namespaceManager;
	}

	/**
	 * Get the grammar name.
	 */
	public String getGrammarName() {
		return grammarName;
	}

	/**
	 * Get the instance name
	 */
	public String getInstanceName() {
		return instanceName;
	}

	/**
	 * Retrieve all the instances at once.
	 * 
	 * @return the instances
	 */
	public Map<String, String> getInstances() {
		return instances;
	}

	/**
	 * @return the qualifiedCorpusName
	 */
	public String getQualifiedCorpusName() {
		return qualifiedCorpusName;
	}

	/**
	 * Get the qualified method name by its declared name.
	 * 
	 * @param name the declared name
	 * @return null if there is no qualified method name associated with the
	 * given name
	 */
	protected String getQualifiedMethodName(String name) {
		if (!instanceName.equals("")) {
			return CharReplacementService.replace(instanceName, '.', '_') + "_" + name;
		}
		return null;
	}

	/**
	 * Get the qualified name by declared instance name
	 * 
	 * @param name get the qualified name of the declared instance name
	 */
	public String getQualifiedName(String name) {
		return instances.get(name);
	}

	/**
	 * if it is an instance, then get its qualified name, otherwise it should be
	 * a grammar, add it to the waiting list.
	 * 
	 * @param value
	 * @return qualified name or grammar name
	 */
	public String getQualifiedOrGrammarName(String value) {
		if (instances.containsKey(value)) {
			// if it is an instance, then get its qualified name
			value = instances.get(value);
			return instances.get(value);
		}
		return null;
	}

	/**
	 * Check whether there is a qualified associated with the given instance
	 * name.
	 * 
	 * @param name instance name
	 */
	public boolean isAnInstance(String name) {
		return instances.containsKey(name);
	}

	/**
	 * Check whether the current grammar is the first grammar among all to be
	 * loaded.
	 * 
	 * @return true if it is.
	 */
	public boolean isPrimaryGrammar() {
		return isPrimaryGrammar;
	}

	/**
	 * Set the coordinator.
	 * 
	 * @param coordinator the coordinator
	 */
	public void setCoordinator(Coordinator c) {
		this.coordinator = c;
	}

	/**
	 * Set up corpus manager.
	 * 
	 * @param namespaceManager the corpusManager to set
	 */
	public void setCorpusManager(NamespaceManager namespaceManager) {
		this.namespaceManager = namespaceManager;
	}

	/**
	 * Set the grammar name;
	 * 
	 * @param grammarName the grammar name
	 */
	public void setGrammarName(String grammarName) {
		this.grammarName = grammarName;
	}

	public void setInstanceName(String gName) {
		this.instanceName = gName;
	}

	/**
	 * Forcefully set up the instances;
	 * 
	 * @param instances the instances to set
	 */
	public void setInstances(Hashtable<String, String> instances) {
		this.instances = instances;
	}

	/**
	 * Set the current grammar to be the first grammar or not.
	 * 
	 * @param isPrimaryGrammar true if it is.
	 */
	public void setIsPrimaryGrammar(boolean isPrimaryGrammar) {
		this.isPrimaryGrammar = isPrimaryGrammar;
	}

	/**
	 * @param qualifiedCorpusName the qualifiedCorpusName to set
	 */
	public void setQualifiedNamespaceName(String qualifiedCorpusName) {
		this.qualifiedCorpusName = qualifiedCorpusName;
	}

}
